local UI = UI

local MakeAccessor = UI.MakeAccessor
local MakeTypeSetter = UI.MakeTypeSetter
local CheckWidgetType = UI.CheckWidgetType
local CheckArgType = UI.CheckArgType
local CheckArgWidget = UI.CheckArgWidget
local IsWidgetType = UI.IsWidgetType

--[[ LayoutFrame ]]--
local LayoutFrame = UI.NewWidgetType("LayoutFrame", "UIObject")
UI.objects["LayoutFrame"].virtual = true

LayoutFrame.parameters = {
	width = 0,
	height = 0,
	visible = true,
	protected = false,
}

function LayoutFrame:Initialize(o)
	local t = UI.params[o]
	t.points = {}
	t.rect = {}
	t.dirty = true
	t.layout_children = {}
	t.layout_parents = {}
	t.animation_groups = {}
end


MakeAccessor("LayoutFrame", "GetAlpha", "alpha")
MakeTypeSetter("LayoutFrame", "SetAlpha", "alpha", "number")

MakeAccessor("LayoutFrame", "IsShown", "visible")
MakeAccessor("LayoutFrame", "IsProtected", "protected")

function LayoutFrame.prototype:ClearAllPoints()
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:ClearAllPoints", self, "LayoutFrame")
	local t = UI.params[self]
	t.points = {}
	for parent in pairs(t.layout_parents) do
		local pt = UI.params[parent]
		pt.layout_children[self] = nil
	end
	t.layout_parents = {}
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:GetBottom()
	CheckWidgetType("LayoutFrame:GetBottom", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.bottom
end

function LayoutFrame.prototype:GetLeft()
	CheckWidgetType("LayoutFrame:GetLeft", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.left
end

function LayoutFrame.prototype:GetRight()
	CheckWidgetType("LayoutFrame:GetRight", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.left + t.width
end

function LayoutFrame.prototype:GetTop()
	CheckWidgetType("LayoutFrame:GetTop", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.bottom + t.height
end

function LayoutFrame.prototype:GetWidth()
	CheckWidgetType("LayoutFrame:GetWidth", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.width
end

function LayoutFrame.prototype:GetHeight()
	CheckWidgetType("LayoutFrame:GetHeight", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.height
end

function LayoutFrame.prototype:GetSize()
	CheckWidgetType("LayoutFrame:GetSize", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.width, t.height
end

function LayoutFrame.prototype:GetCenter()
	CheckWidgetType("LayoutFrame:GetCenter", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.left + t.width / 2, t.bottom + t.height / 2
end

function LayoutFrame.prototype:GetNumPoints()
	CheckWidgetType("LayoutFrame:GetNumPoints", self, "LayoutFrame")
	local t = UI.params[self]
	return #t.points
end

function LayoutFrame.prototype:GetParent()
	CheckWidgetType("LayoutFrame:GetParent", self, "LayoutFrame")
	return UI.GetParent(self)
end

function LayoutFrame.prototype:GetPoint(pointNum)
	CheckWidgetType("LayoutFrame:GetPoint", self, "LayoutFrame")
	CheckArgType("LayoutFrame:GetPoint", 2, "pointNum", {"number", "nil"}, pointNum)
	local t = UI.params[self]
	local p = t.points[pointNum or 1]
	if p then
		return p.point, p.relativeFrame, p.relativePoint, p.offsetx, p.offsety
	end
end

function LayoutFrame.prototype:IsVisible()
	CheckWidgetType("LayoutFrame:IsVisible", self, "LayoutFrame")
	return UI.Visible(self)
end

function LayoutFrame.prototype:SetAllPoints(frame)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetAllPoints", self, "LayoutFrame")
	-- CheckArgWidget("LayoutFrame:SetAllPoints", 2, "frame", "LayoutFrame", frame)
	self:SetPoint("TOPLEFT", frame)
	self:SetPoint("BOTTOMRIGHT", frame)
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:SetHeight(height)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetHeight", self, "LayoutFrame")
	CheckArgType("LayoutFrame:SetHeight", 2, "height", "number", height)
	local t = UI.params[self]
	t.height = height
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:SetParent(parent)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetParent", self, "LayoutFrame")
	if type(parent) == "string" then
		parent = UI.GetGlobal(parent)
	end
	if parent then
		CheckArgWidget("LayoutFrame:SetParent", 2, "parent", "LayoutFrame", parent)
	end
	UI.Reparent(self, parent)
end

local VALID_POINTS = {
	LEFT = true,
	RIGHT = true,
	TOP = true,
	BOTTOM = true,
	CENTER = true,
	TOPLEFT = true,
	TOPRIGHT = true,
	BOTTOMLEFT = true,
	BOTTOMRIGHT = true,
}

function LayoutFrame.prototype:SetPoint(point, ...)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetPoint", self, "LayoutFrame")
	CheckArgType("LayoutFrame:SetPoint", 2, "point", "string", point)
	if not VALID_POINTS[point] then
		error(string.format("In LayoutFrame:SetPoint(), parameter 2 (point). Invalid value %q", point))
	end
	local frame, rpoint, x, y
	local count = select("#", ...)

	local t = UI.params[self]
	if count ==  0 then
		frame = t.parent
		rpoint = point
		x = 0
		y = 0
	elseif count == 1 then
		frame = select(1, ...) or t.parent
		rpoint = point
		x = 0
		y = 0
	elseif count == 2 then
		if type(select(1, ...)) == "number" then
			frame = t.parent
			rpoint = point
			x = select(1, ...)
			y = select(2, ...)
		else
			frame = select(1, ...) or t.parent
			rpoint = select(2, ...) or point
			x = 0
			y = 0
		end
	elseif count == 3 then
		frame = select(1, ...) or t.parent
		rpoint = point
		x = select(2, ...) or 0
		y = select(3, ...) or 0
	elseif count == 4 then
		frame = select(1, ...) or t.parent
		rpoint = select(2, ...) or point
		x = select(3, ...) or 0
		y = select(4, ...) or 0
	else
		error(string.format("In LayoutFrame:SetPoint(), invalid number of parameters (%d)",  count))
	end
	if type(frame) == "string" then
		if frame:find("$parent", nil, 1) then
			local parent = assert(self:GetParent())
			local pname = assert(UI.GetName(parent, true))
			frame = frame:gsub("$parent", pname)
		end
		frame = UI.GetGlobal(frame)
	end
	if frame then
		CheckArgWidget("LayoutFrame:SetPoint", 3, "frame", "LayoutFrame", frame)
	end
	CheckArgType("LayoutFrame:SetPoint", 4, "rpoint", "string", rpoint)
	CheckArgType("LayoutFrame:SetPoint", 5, "x", "number", x)
	CheckArgType("LayoutFrame:SetPoint", 6, "y", "number", y)

	point, rpoint = point:upper(), rpoint:upper()

	if not VALID_POINTS[rpoint] then
		error(string.format("In LayoutFrame:SetPoint(), Invalid value %q for relativePoint", rpoint))
	end

	local index = #t.points + 1
	for i = 1, #t.points do
		if t.points[i].point == point then index = i break end
	end

	t.points[index] = {
		point = point,
		relativeFrame = frame,
		relativePoint = rpoint,
		offsetx = x,
		offsety = y,
	}
	if frame then
		t.layout_parents[frame] = true
		UI.params[frame].layout_children[self] = true
	end
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:SetWidth(width)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetWidth", self, "LayoutFrame")
	CheckArgType("LayoutFrame:SetWidth", 2, "width", "number", width)
	local t = UI.params[self]
	t.width = width
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:SetSize(width, height)
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:SetSize", self, "LayoutFrame")
	CheckArgType("LayoutFrame:SetSize", 2, "width", "number", width)
	CheckArgType("LayoutFrame:SetSize", 3, "height", "number", height)
	local t = UI.params[self]
	t.width = width
	t.height = height
	UI.SetDirtyLayout(self)
end

function LayoutFrame.prototype:Hide()
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:Hide", self, "LayoutFrame")
	local t = UI.params[self]
	local v = UI.Visible(self)
	t.visible = false
	if v then
		UI.CallScript(self, "OnHide")
	end
end

function LayoutFrame.prototype:Show()
	if api.incombat() then return end
	CheckWidgetType("LayoutFrame:Show", self, "LayoutFrame")
	local t = UI.params[self]
	local v = UI.Visible(self)
	t.visible = true
	if not v and UI.Visible(self) then
		UI.CallScript(self, "OnShow")
	end
end

function LayoutFrame.prototype:GetRect()
	CheckWidgetType("LayoutFrame:GetRect", self, "LayoutFrame")
	UI.Layout(self)
	local t = UI.params[self].rect
	return t.left, t.bottom, t.width, t.height
end

